{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.6.9"
    },
    "colab": {
      "name": "Part 04 - Federated Learning via Trusted Aggregator.ipynb",
      "provenance": [],
      "collapsed_sections": []
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Pi1ValLVWnnU",
        "colab_type": "text"
      },
      "source": [
        "# পর্ব ৪ঃ মডেল গড়ের মাধ্যমে ফেডারেটেড লার্নিং\n",
        "\n",
        "**ফিরে দেখা:** টিউটোরিয়ালের পর্ব-২ এ আমরা ফেডারেটেড লার্নিং এর সাধারণ ভার্সন দিয়ে একটি মডেল ট্রেইন করেছিলাম। এক্ষেত্রে প্রতিটি তথ্যের অধিকারীকে তাদের গ্রেডিয়েন্টের জন্য মডেল অধিকারীর উপর বিশ্বাস রাখা প্রয়োজনীয় ছিল।\n",
        "\n",
        "**বিবরণ:** এই টিউটোরিয়ালে আমরা দেখবো - চূড়ান্ত মডেলকে মডেল অধিকারীর কাছে পাঠানোর আগে কিভাবে পর্ব ৩ এর উন্নীত একত্রিকরণ সরঞ্জাম সমূহ ব্যবহার করে বিশ্বস্ত \"secure worker\" এর মাধ্যমে ওয়েটগুলো(weights) একত্রিকরণ করা হয়।\n",
        "\n",
        "এই পন্থায় শুধুমাত্র নিরাপদ কর্মী দেখতে পারে কার ওয়েটগুলো(weights) কার কাছ থেকে এসেছে। আমরা হয়তো বলবো পারবো মডেল কোথায় কি পরিবর্তন এসেছে কিন্তু আমরা জানতে পারবো না কোন কর্মী কোন পরিবর্তনের জন্য দায়ী। যা কি-না গোপনীয়তার একটি আস্তরণ তৈরি করে।\n",
        "\n",
        "লেখকঃ\n",
        " - Andrew Trask - Twitter: [@iamtrask](https://twitter.com/iamtrask)\n",
        " - Jason Mancuso - Twitter: [@jvmancuso](https://twitter.com/jvmancuso)\n",
        "\n",
        "অনুবাদকঃ\n",
        " - মীর মোহাম্মদ জাবের(Mir Mohammad Jaber) - Twitter: [@jabertuhin](https://twitter.com/jabertuhin)"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "EgtylnIiWnnb",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "import torch\n",
        "import syft as sy\n",
        "import copy\n",
        "hook = sy.TorchHook(torch)\n",
        "from torch import nn, optim"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oU1DqwBZWnnm",
        "colab_type": "text"
      },
      "source": [
        "# ধাপ ১ঃ ডাটা অধিকারী তৈরি করি\n",
        "\n",
        "প্রথমে আমরা অল্প কিছু তথ্য দিয়ে বব(Bob) ও এলিস(Alice) নামে দু'টি তথ্য অধিকারী তৈরি করি। আমরা এর সাথে \"secure_worker\" নামে একটি নিরাপদ মেশিন তৈরি করি। কাজের ক্ষেত্রে এটি নিরাপদ কোন হার্ডওয়্যার(যেমন - Intel's SGX) কিংবা সাধারণ কোন বিশ্বস্ত মাধ্যম হতে পারে।"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "FNxNZuCWWnno",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# create a couple workers\n",
        "\n",
        "bob = sy.VirtualWorker(hook, id=\"bob\")\n",
        "alice = sy.VirtualWorker(hook, id=\"alice\")\n",
        "secure_worker = sy.VirtualWorker(hook, id=\"secure_worker\")\n",
        "\n",
        "\n",
        "# A Toy Dataset\n",
        "data = torch.tensor([[0,0],[0,1],[1,0],[1,1.]], requires_grad=True)\n",
        "target = torch.tensor([[0],[0],[1],[1.]], requires_grad=True)\n",
        "\n",
        "# get pointers to training data on each worker by\n",
        "# sending some training data to bob and alice\n",
        "bobs_data = data[0:2].send(bob)\n",
        "bobs_target = target[0:2].send(bob)\n",
        "\n",
        "alices_data = data[2:].send(alice)\n",
        "alices_target = target[2:].send(alice)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8ig5T1pLWnnz",
        "colab_type": "text"
      },
      "source": [
        "# ধাপ ২ঃ আমাদের মডেল তৈরি করি\n",
        "\n",
        "এই উদাহরণে আমরা একটি সাধারণ লিনিয়ার মডেল তৈরি করবো। আমরা এটি Pytorch এর nn.Linear কন্সট্রাকটর ব্যবহার করে তৈরি করতে পারি।"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "25xc1FqmWnn2",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# Iniitalize A Toy Model\n",
        "model = nn.Linear(2,1)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "beR58JTzWnoL",
        "colab_type": "text"
      },
      "source": [
        "# ধাপ ৩ঃ মডেলের একটা অনুলিপি বব(Bob) ও এলিস(Alice) কে পাঠাই\n",
        "\n",
        "অতঃপর মডেলের একটা অনুলিপি আমরা বব(Bob) ও এলিস(Alice) কে দিই যেন তারা নিজেদের ডাটাসেটের উপর লার্নিং পদক্ষেপগুলো চালাতে পারে।"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Jj6oOQDbWnoP",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "bobs_model = model.copy().send(bob)\n",
        "alices_model = model.copy().send(alice)\n",
        "\n",
        "bobs_opt = optim.SGD(params=bobs_model.parameters(),lr=0.1)\n",
        "alices_opt = optim.SGD(params=alices_model.parameters(),lr=0.1)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "4xzkHnmuWnoT",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        ""
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uu9_2cgNWnoZ",
        "colab_type": "text"
      },
      "source": [
        "# ধাপ ৪ঃ বব(Bob) ও এলিস(Alice) এর মডেল ট্রেইন করা(সমান্তরালি)\n",
        "\n",
        "ফেডারেটেড লার্নিং এর মাধ্যমে প্রচলিতভাবে যেভাবে নিরাপদ গড় করা হয়ে থাকে - দু'টি মডেল গড় করে একত্রিত করার আগে প্রত্যেক তথ্যের অধিকারী প্রথমে তাদের মডেল কয়েকবার করে স্থানীয়ভাবে ট্রেইন করে।"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "iUr2cgEuWnob",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "for i in range(10):\n",
        "\n",
        "    # Train Bob's Model\n",
        "    bobs_opt.zero_grad()\n",
        "    bobs_pred = bobs_model(bobs_data)\n",
        "    bobs_loss = ((bobs_pred - bobs_target)**2).sum()\n",
        "    bobs_loss.backward()\n",
        "\n",
        "    bobs_opt.step()\n",
        "    bobs_loss = bobs_loss.get().data\n",
        "\n",
        "    # Train Alice's Model\n",
        "    alices_opt.zero_grad()\n",
        "    alices_pred = alices_model(alices_data)\n",
        "    alices_loss = ((alices_pred - alices_target)**2).sum()\n",
        "    alices_loss.backward()\n",
        "\n",
        "    alices_opt.step()\n",
        "    alices_loss = alices_loss.get().data\n",
        "    \n",
        "    print(\"Bob:\" + str(bobs_loss) + \" Alice:\" + str(alices_loss))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3TSy7TaZWnoi",
        "colab_type": "text"
      },
      "source": [
        "# ধাপ ৫ঃ উভয় হালনাগাদকৃত(updated) মডেলকে নিরাপদ কর্মীর কাছে পাঠানো\n",
        "\n",
        "এখন প্রতিটা তথ্যের অধিকারী এর কাছে আংশিক ট্রেইনড মডেল আছে, এই সময় সেগুলো নিরাপদভাবে গড় করে একত্রিত করতে হবে। বব(Bob) ও এলিস(Alice) কে তাদের মডেল নিরাপদ (বিশ্বস্ত) সার্ভারে পাঠাতে বলার মাধ্যমে আমরা তা করতে পারি।\n",
        "খেয়াল করি, আমাদের API এর এই ব্যবহারের মাধ্যমে প্রতিটা মডেল সরাসরি secure_worker এর কাছে চলে যায়। আমরা কখনো তা দেখতে পারি না।"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "jDq2EhDmWnok",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "alices_model.move(secure_worker)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "XNmFgq8QWnop",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "bobs_model.move(secure_worker)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lDb9r2CNWnox",
        "colab_type": "text"
      },
      "source": [
        "# ধাপ ৬ঃ মডেলগুলোর গড় করি"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mtdIQeybWnoz",
        "colab_type": "text"
      },
      "source": [
        "পরিশেষে, এই ট্রেইনিং ইপোক(epoch) এর শেষ ধাপে বব ও এলিসের ট্রেইনড মডেল দু'টো গড় করে একত্রিত করবো এবং এর মাধ্যমে আমাদের গ্লোবাল মডেলের মান নির্ধারণ করবো।"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "YP-orP5fWno0",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "with torch.no_grad():\n",
        "    model.weight.set_(((alices_model.weight.data + bobs_model.weight.data) / 2).get())\n",
        "    model.bias.set_(((alices_model.bias.data + bobs_model.bias.data) / 2).get())\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "q9nLH9IIWno5",
        "colab_type": "text"
      },
      "source": [
        "# পরিষ্কার করে পুনরাবৃত্তি\n",
        "\n",
        "আর এখন আমাদেরকে শুধু এই কাজ কয়েকবার করে করতে হবে।"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "mZw9O5INWno6",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "iterations = 10\n",
        "worker_iters = 5\n",
        "\n",
        "for a_iter in range(iterations):\n",
        "    \n",
        "    bobs_model = model.copy().send(bob)\n",
        "    alices_model = model.copy().send(alice)\n",
        "\n",
        "    bobs_opt = optim.SGD(params=bobs_model.parameters(),lr=0.1)\n",
        "    alices_opt = optim.SGD(params=alices_model.parameters(),lr=0.1)\n",
        "\n",
        "    for wi in range(worker_iters):\n",
        "\n",
        "        # Train Bob's Model\n",
        "        bobs_opt.zero_grad()\n",
        "        bobs_pred = bobs_model(bobs_data)\n",
        "        bobs_loss = ((bobs_pred - bobs_target)**2).sum()\n",
        "        bobs_loss.backward()\n",
        "\n",
        "        bobs_opt.step()\n",
        "        bobs_loss = bobs_loss.get().data\n",
        "\n",
        "        # Train Alice's Model\n",
        "        alices_opt.zero_grad()\n",
        "        alices_pred = alices_model(alices_data)\n",
        "        alices_loss = ((alices_pred - alices_target)**2).sum()\n",
        "        alices_loss.backward()\n",
        "\n",
        "        alices_opt.step()\n",
        "        alices_loss = alices_loss.get().data\n",
        "    \n",
        "    alices_model.move(secure_worker)\n",
        "    bobs_model.move(secure_worker)\n",
        "    with torch.no_grad():\n",
        "        model.weight.set_(((alices_model.weight.data + bobs_model.weight.data) / 2).get())\n",
        "        model.bias.set_(((alices_model.bias.data + bobs_model.bias.data) / 2).get())\n",
        "    \n",
        "    print(\"Bob:\" + str(bobs_loss) + \" Alice:\" + str(alices_loss))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "OMaS-ZpDWnpA",
        "colab_type": "text"
      },
      "source": [
        "সবশেষে আমরা নিশ্চিত হতে চাই যে আমাদের মডেল ঠিকঠাকভাবে শিখেছে। তাই আমরা এটিকে টেস্ট ডাটাসেটের উপরে মূল্যায়ন করবো। আমাদের তৈরি করা এই মিছে সমস্যার ক্ষেত্রে আমরা আসল তথ্যই ব্যবহার করছি। কিন্তু বাস্তবে আমরা নতুন তথ্য দিয়ে বুঝতে চেষ্টা করি আমাদের মডেল অদেখা উদাহরণ কতটা জেনারেলাইজ করে।"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "eIsXKn59WnpC",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "preds = model(data)\n",
        "loss = ((preds - target) ** 2).sum()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "-4KIEFTHWnpM",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "print(preds)\n",
        "print(target)\n",
        "print(loss.data)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v5A2tHahWnpW",
        "colab_type": "text"
      },
      "source": [
        "আমাদের এই উদাহরণের ক্ষেত্রে, গড় মডেল সাধারণ স্থানীয় ট্রেইন্ড মডেলের থেকে বেশি আন্ডারফিট(underfit) করছে। যদিও আমরা তা করতে পেরেছি কোন কর্মীর ট্রেইনিং ডাটা অন্য আরেকজনের কাছে উন্মুক্ত না করে। আমরা কোন তথ্য মডেল অধিকারীর কাছে প্রকাশ না করেই, হালনাগাদকৃত মডেলগুলো একটি বিশ্বস্ত সংযোগকারীর মাধ্যমে একত্রিত করতে পেরেছি।\n",
        "\n",
        "ভবিষ্যত টিউটোরিয়ালে, আমাদের লক্ষ্য থাকবে সরাসরি গ্রেডিয়েন্টে বিশ্বস্ত একত্রিকরণ করতে পারা। যেন আমরা মডেল আরো ভালো গ্রেডিয়েন্ট এস্টিমেটস দিয়ে হালনাগাদ করতে পারি এবং আরো জোরালো মডেল পাই।"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "XB4WXTmmWnpZ",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        ""
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GnJ2LUXxWnpd",
        "colab_type": "text"
      },
      "source": [
        "# অভিনন্দন!!! - আমাদের কমিউনিটিতে যোগদান করুন\n",
        "\n",
        "এই নোটবুক টিউটোরিয়ালটি শেষ করার জন্য অভিনন্দন! আপনি যদি এটি পছন্দ করে থাকেন এবং গোপনীয়তা সংরক্ষণ, কৃত্রিম বুদ্ধিমত্তার অধিকারের বিকেন্দ্রিকরণ এবং এর সাপ্লাই চেইনের(তথ্য) আন্দোলনে যোগ দিতে চান তাহলে আপনি নিম্নোক্ত পন্থা অনুসারে তা করতে পারেন।\n",
        "\n",
        "### PySyft -কে গিটহাবে স্টার দিন\n",
        "\n",
        "আমাদের কমিউনিটিকে সাহায্য করার সবচেয়ে সহজ পন্থা হলো রিপোজিটোরিতে স্টার দেয়া! এটি আমরা যে দারুন সরঞ্জাম তৈরি করছি সে ব্যাপারে সচেতনতা বৃদ্ধি করতে সাহায্য করে।\n",
        "\n",
        "- [Star PySyft](https://github.com/OpenMined/PySyft)\n",
        "\n",
        "### আমাদের স্ল্যাকে(Slack) যোগ দিন!\n",
        "\n",
        "নতুন নতুন অগগ্রতির সাথে নিজেকে টিকিয়ে রাখার সেরা উপায় হলো আমাদের কমিউনিটিতে যোগ দেয়া! আর তা করার জন্য উল্লিখিত ফর্মটি পূরণ করতে হবে [http://slack.openmined.org](http://slack.openmined.org)\n",
        "\n",
        "### কোড প্রজেক্টে যোগ দিন!\n",
        "\n",
        "আমাদের কমিউনিটিতে অবদান রাখার সেরা উপায় হলো একজন কোড অবদানকারীতে পরিণত হওয়া। যেকোন সময় আপনি PySyft এর গিটহাব ইস্যুর পেজে যেতে পারেন এবং \"Projects\" দিয়ে বাছাই করবেন। এর মাধ্যমে আপনি যে সকল প্রজেক্টে যোগদান করতে পারবেন সেগুলোর উপরের দিকের টিকেটের ওভারভিউ পাবেন। আপনি যদি কোন প্রজেক্টে জয়েন করতে ইচ্ছুক না হোন, কিন্তু কিছুটা কোডিং করতে ইচ্ছুক সেক্ষেত্রে আপনি \"one off\" মিনি প্রজেক্টগুলো দেখতে পারেন গিটহাব ইস্যুতে \"good first issue\" চিহ্নিত ইস্যুগুলো।\n",
        "\n",
        "- [PySyft Projects](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3AProject)\n",
        "- [Good First Issue Tickets](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
        "\n",
        "### দান করুন\n",
        "\n",
        "আপনার যদি আমাদের কোডবেজে অবদান রাখারা সময় না হয়, কিন্তু এরপরও আমাদেরকে সমর্থন দিতে চান তাহলে আমাদের উন্মুক্ত সংগ্রহের সমর্থক হতে পারেন। সকল ধরনের দানের অর্থ আমাদের ওয়েব হোস্টিং এবং অন্যান্য কমিউনিটি কার্যক্রমে খরচ হয় যেমন - হ্যাকাথন, মিটাপ।\n",
        "\n",
        "[OpenMined's Open Collective Page](https://opencollective.com/openmined)"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "GyQ53OVZWnpg",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        ""
      ],
      "execution_count": 0,
      "outputs": []
    }
  ]
}